package org.qtmo.emu.nes;
import flash.Lib;
import flash.Memory;
import flash.utils.ByteArray;

/**
 * NES Memory Management Unit
 * ...
 * @author Sang Hua Cai
 */

class MMU 
{

	/**************************************************************
	 * ----------------------- Memory Map -------------------------
	 * CPU Memory 64K       						offset  0x00000
	 * PPU Memory 16K							    offset  0x10000
	 **************************************************************
	 */
	// size 64K   0x00000~0x0FFFF    0x10000
	public static inline var CPU_BANK_OFFSET:UInt 		= 0x00000;
	// size 16K   0x10000~0x13FFF    0x4000
	public static inline var PPU_BANK_OFFSET:UInt		= 0x10000;	
	// size 256   负数表             0x100
	public static inline var ZN_TABLE_OFFSET:UInt 		= 0x14000;
	// size 256   Sprite RAM         0x100
	public static inline var SPRAM_OFFSET:UInt 			= 0x14100;
	// size 64k   screen 256*140     0x10000
	public static inline var SCREEN_OFFSET:UInt 		= 0x14200;
	// size 256   scanline color     0x100
	public static inline var SCANLINE_COLOR_OFFSET:UInt = 0x24200;
	
	// tmp size 1M         rom file
	public static inline var ROM_OFFSET:UInt			= 0x100000;
	
	// in cpu bank
	public static inline var PPU_REG_OFFSET:UInt 		= 0x02000;
	public static inline var STACK_OFFSET:UInt			= 0x00100;
	// in ppu bank
	public static inline var BGPAL_OFFSET:UInt			= 0x13F00;
	public static inline var SPPAL_OFFSET:UInt			= 0x13F10;
	

	public function new(nes:NES)
	{
		this.nes = nes;
	}
	
	public function Initialize():Void
	{
		//var tmp:UInt;
		
		memory = new ByteArray();
		var time:UInt = Lib.getTimer();
		for (i in 0...0x300000)
		{
			memory.writeByte(0);
		}
		trace(Lib.getTimer() - time);

		Memory.select(memory);
		/*
		var time:UInt = Lib.getTimer();
		for (i in 0...0x200000)
		{
			tmp = Read(i);
		}
		trace(Lib.getTimer() - time);
		
		var time:UInt = Lib.getTimer();
		for (i in 0...0x200000)
		{
			tmp = Read(i);
		}
		trace(Lib.getTimer() - time);
		*/
	}
	
	public static inline function Read(addr:UInt):UInt
	{
		return Memory.getByte(addr);
	}
	
	public static inline function Write(addr:UInt, value:UInt):Void
	{
		Memory.setByte(addr, value);
	}
	
	private var nes:NES;
	
	private var memory:ByteArray;
}